/*
 * @file log.h
 * @auther ChenYang
 *
 * @date 2014/11/30
 */

#ifndef _UTILS_LOG_H_
#define _UTILS_LOG_H_

#include <stdio.h>
#include <errno.h>
#include <string.h>

/* log levels the same as syslog */
#define __LOG_LV_EMERG (0)
#define __LOG_LV_ALERT (1)
#define __LOG_LV_CRIT (2)
#define __LOG_LV_ERR (3)
#define __LOG_LV_WARN (4)
#define __LOG_LV_NOTICE (5)
#define __LOG_LV_INFO (6)
#define __LOG_LV_DEBUG (7)

/* colors */
#define __LOG_CL_NONE "\e[0m"
#define __LOG_CL_BLACK "\e[0;30m"
#define __LOG_CL_L_BLACK "\e[1;30m"
#define __LOG_CL_RED "\e[0;31m"
#define __LOG_CL_L_RED "\e[1;31m"
#define __LOG_CL_GREEN "\e[32m"
#define __LOG_CL_L_GREEN "\e[1;32m"
#define __LOG_CL_BROWN "\e[0;33m"
#define __LOG_CL_YELLOW "\e[1;33m"
#define __LOG_CL_BLUE "\e[0;34m"
#define __LOG_CL_L_BLUE "\e[1;34m"
#define __LOG_CL_PURPLE "\e[0;35m"
#define __LOG_CL_L_PURPLE "\e[1;35m"
#define __LOG_CL_CYAN "\e[0;36m"
#define __LOG_CL_L_CYAN "\e[1;36m"
#define __LOG_CL_GRAY "\e[0;37m"
#define __LOG_CL_WHITE "\e[1;37m"

#define __LOG_CL_BOLD "\e[1m"
#define __LOG_CL_UNDERLINE "\e[4m"
#define __LOG_CL_BLINK "\e[5m"
#define __LOG_CL_REVERSE "\e[7m"
#define __LOG_CL_HIDE "\e[8m"
#define __LOG_CL_CLEAR "\e[2J"
#define __LOG_CL_CLRLINE "\r\e[K" // or "\e[1K\r"

#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

#ifndef LOG_LEVEL
#define LOG_LEVEL __LOG_LV_DEBUG
#endif

#ifndef LOG_COLOR
#define LOG_COLOR (1)
#endif

/* safe readable version of errno */
#define clean_errno() (errno == 0 ? "None" : strerror(errno))

#define log_emerg(M, ...) fprintf(stdout, __LOG_CL_L_RED "[EMERG]" __LOG_CL_NONE " %s (%s:%d) " M " errno: %s\n", \
                                  __func__, __FILENAME__, __LINE__, ##__VA_ARGS__, clean_errno());
#define log_alert(M, ...) fprintf(stdout, __LOG_CL_YELLOW "[ALERT]" __LOG_CL_NONE " %s (%s:%d) " M " errno: %s\n", \
                                  __func__, __FILENAME__, __LINE__, ##__VA_ARGS__, clean_errno());
#define log_crit(M, ...) fprintf(stdout, __LOG_CL_L_PURPLE "[CRIT]" __LOG_CL_NONE "  %s (%s:%d) " M " errno: %s\n", \
                                 __func__, __FILENAME__, __LINE__, ##__VA_ARGS__, clean_errno());
#define log_err(M, ...) fprintf(stdout, __LOG_CL_RED "[ERR]" __LOG_CL_NONE "   %s (%s:%d) " M " errno: %s\n", \
                                __func__, __FILENAME__, __LINE__, ##__VA_ARGS__, clean_errno());
#define log_warn(M, ...) fprintf(stdout, __LOG_CL_YELLOW "[WARN]" __LOG_CL_NONE "  %s (%s:%d) " M " errno: %s\n", \
                                 __func__, __FILENAME__, __LINE__, ##__VA_ARGS__, clean_errno());
#define log_notice(M, ...) fprintf(stdout, __LOG_CL_CYAN "[NOTICE]" __LOG_CL_NONE "(%s:%d) " M "\n", \
                                   __FILENAME__, __LINE__, ##__VA_ARGS__);
#define log_info(M, ...) fprintf(stdout, "[INFO]  (%s:%d) " M "\n", __FILENAME__, __LINE__, ##__VA_ARGS__);
#define log_debug(M, ...) fprintf(stdout, "[DEBUG] (%s:%d) " M "\n", __FILENAME__, __LINE__, ##__VA_ARGS__);

/* LOG_LEVEL controls */
#if LOG_LEVEL < __LOG_LV_DEBUG
#undef log_debug
#define log_debug(M, ...) \
    do                    \
    {                     \
    } while (0)
#endif

#if LOG_LEVEL < __LOG_LV_INFO
#undef log_info
#define log_info(M, ...) \
    do                   \
    {                    \
    } while (0)
#endif

#if LOG_LEVEL < __LOG_LV_NOTICE
#undef log_notice
#define log_notice(M, ...) \
    do                     \
    {                      \
    } while (0)
#endif

#if LOG_LEVEL < __LOG_LV_WARN
#undef log_warn
#define log_warn(M, ...) \
    do                   \
    {                    \
    } while (0)
#endif

#if LOG_LEVEL < __LOG_LV_ERR
#undef log_err
#define log_err(M, ...) \
    do                  \
    {                   \
    } while (0)
#endif

#if LOG_LEVEL < __LOG_LV_CRIT
#undef log_crit
#define log_crit(M, ...) \
    do                   \
    {                    \
    } while (0)
#endif

#if LOG_LEVEL < __LOG_LV_ALERT
#undef log_alert
#define log_alert(M, ...) \
    do                    \
    {                     \
    } while (0)
#endif

#if LOG_LEVEL < __LOG_LV_EMERG
#undef log_emerg
#define log_emerg(M, ...) \
    do                    \
    {                     \
    } while (0)
#endif

/* LOG_COLOR controls */
#if LOG_COLOR < 1

#undef __LOG_CL_NONE
#define __LOG_CL_NONE

#undef __LOG_CL_RED
#define __LOG_CL_RED

#undef __LOG_CL_PURPLE
#define __LOG_CL_PURPLE

#undef __LOG_CL_YELLOW
#define __LOG_CL_YELLOW

#undef __LOG_CL_BROWN
#define __LOG_CL_BROWN

#undef __LOG_CL_GREEN
#define __LOG_CL_GREEN

#undef __LOG_CL_CYAN
#define __LOG_CL_CYAN

#undef __LOG_CL_BLUE
#define __LOG_CL_BLUE

#undef __LOG_CL_GRAY
#define __LOG_CL_GRAY

#endif

#undef __LOG_LV_EMERG
#undef __LOG_LV_ALERT
#undef __LOG_LV_CRIT
#undef __LOG_LV_ERR
#undef __LOG_LV_WARN
#undef __LOG_LV_NOTICE
#undef __LOG_LV_INFO
#undef __LOG_LV_DEBUG

#endif /* _UTILS_LOG_H_*/
